/*
 * Copyright (c) 2015-2018 Sfkj Science And Technology Co.,Ltd.
 * All Rights Reserved.
 * This software is the confidential and proprietary information of
 * Sfkj Science And Technology Co.,Ltd.
 * ("Confidential Information").You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sfkj.
 */
package com.sfkj.walk.command.activity;

import com.google.common.base.Preconditions;
import com.sfkj.walk.api.activity.*;
import com.sfkj.walk.api.activity.ActivityMemberType;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.commandhandling.model.AggregateIdentifier;
import org.axonframework.commandhandling.model.AggregateMember;
import org.axonframework.eventhandling.MetaDataConstants;
import org.axonframework.eventsourcing.EventSourcingHandler;
import org.axonframework.messaging.annotation.MetaDataValue;
import org.axonframework.spring.stereotype.Aggregate;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static org.axonframework.commandhandling.model.AggregateLifecycle.apply;
import static org.axonframework.commandhandling.model.AggregateLifecycle.markDeleted;

@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Getter
@Aggregate
@EqualsAndHashCode(of = "id")
public class Activity {

    @AggregateIdentifier
    private String id;
    @Getter
    private String creatorId;
    @AggregateMember
    @Getter
    private List<ActivityMember> members = new ArrayList<>();


    @CommandHandler
    public Activity(CreateActivityCommand command, @MetaDataValue(MetaDataConstants.CURRENT_USER_ID) String currentUserId) {
        ActivityCreatedEvent event = new ActivityCreatedEvent();
        BeanUtils.copyProperties(command, event);
        apply(event);

        joinMember(command.getId(), currentUserId);
    }

    @CommandHandler
    public void change(ChangeActivityCommand command) {
        ActivityChangedEvent event = new ActivityChangedEvent();
        BeanUtils.copyProperties(command, event);
        apply(event);
    }

    @CommandHandler
    public void delete(DeleteActivityCommand command) {
        ActivityDeletedEvent event = new ActivityDeletedEvent();
        BeanUtils.copyProperties(command, event);
        apply(event);
    }


    public void joinMember(String userId) {
        joinMember(getId(), userId);
    }

    public void joinMember(String id, String userId) {
        Preconditions.checkState(!members.contains(new ActivityMember((userId))), "用户已经加入该活动");

        MemberJoinedEvent event = new MemberJoinedEvent();
        event.setId(id);
        event.setActivityMemberType(
                Objects.equals(creatorId, userId) ? ActivityMemberType.CREATOR : ActivityMemberType.MEMBER
        );
        apply(event);
    }

    @CommandHandler
    public void removeMember(RemoveMemberCommand command, @MetaDataValue(MetaDataConstants.CURRENT_USER_ID) String currentUserId) {
        MemberRemovedEvent event = new MemberRemovedEvent();
        BeanUtils.copyProperties(command, event);
        apply(event);
    }


    @EventSourcingHandler
    public void on(ActivityCreatedEvent event, @MetaDataValue(MetaDataConstants.CURRENT_USER_ID) String currentUserId) {
        this.id = event.getId();
        this.creatorId = currentUserId;
    }

    @EventSourcingHandler
    public void on(ActivityDeletedEvent event) {
        markDeleted();
    }

    @EventSourcingHandler
    public void on(MemberJoinedEvent event, @MetaDataValue(MetaDataConstants.CURRENT_USER_ID) String currentUserId) {
        this.members.add(new ActivityMember(currentUserId));
    }

    @EventSourcingHandler
    public void on(MemberRemovedEvent event) {
        this.members.remove(new ActivityMember(event.getUserId()));
    }

}